package net.cloudcodex.shared.rpc;

import java.util.Date;
import java.util.List;
import java.util.Map;

import net.cloudcodex.shared.Errors;
import net.cloudcodex.shared.MessageAction;
import net.cloudcodex.shared.dto.Result;
import net.cloudcodex.shared.dto.campaign.character.CharacterDescriptionDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterHeaderDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterNoteDTO;
import net.cloudcodex.shared.dto.campaign.character.CompleteCharacterDescriptionDTO;
import net.cloudcodex.shared.dto.home.CampaignSummaryDTO;
import net.cloudcodex.shared.dto.msg.SceneDTO;
import net.cloudcodex.shared.dto.msg.SceneToCreateDTO;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("campaign")
public interface CampaignRPC extends RemoteService {

	/**
	 * Creates a campaign.
	 * 
	 * @param name name of the campaign to create.
	 * @param game game of the campaign to create.
	 * @param description campaign's description, visible before joining it.
	 * @param icon url for the campaign's icon.
	 * @return the newly created campaign.
	 * @see Errors#IMPOSSIBLE_EXISTS
	 */
	public Result<CampaignSummaryDTO> createCampaign(String name, String game,
			String description, String icon);
	
	
	/**
	 * Updates a campaign. Be careful, notifications and characters are 
	 * not re-read and then not returned here.
	 * 
	 * @param campaign id of the campaign to update.
	 * @param name name of the campaign to create.
	 * @param game game of the campaign to create.
	 * @param description campaign's description, visible before joining it.
	 * @param icon url for the campaign's icon.
	 * @return the newly created campaign.
	 * @see Errors#IMPOSSIBLE_EXISTS if the name is already used
	 */
	public Result<CampaignSummaryDTO> updateCampaign(long campaignId, 
			String name, String game,
			String description, String icon);
	
	/**
	 * Gives the last messages of the campaign for a character.
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param lastSceneId for pagination, your last scene read. may be null.
	 * @param timestamp for delta, your last update date. 
	 * 		When not null, lastSceneId is not used.
	 * @return the last messages of the characters. scenes are limited but complete.
	 */
	public Result<List<SceneDTO>> getMessages(
			long campaignId, long characterId,
			Long lastSceneId, Date timestamp);
	
	/**
	 * Temporary method to invit someone to a campaign.
	 * @param campaignId campaign id.
	 * @param email email of the user.
	 * @param name Name of the character to create.
	 * @return the created character
	 * @see Errors#IMPOSSIBLE_EXISTS
	 * @see Errors#IMPOSSIBLE_ITSELF
	 */
	public Result<CharacterHeaderDTO> inviteToCampaign(
			long campaignId, String email, String name);
	
	/**
	 * Creates a NPC.
	 * @param campaignId campaign's id.
	 * @param name NPC's name.
	 * @param description NPC's public description, can be null.
	 * @param icon NPC's icon, can be null;
	 * @param profile <code>true</code> for profiles.
	 * @return the NPC's header to update client cache.
	 * @see Errors#IMPOSSIBLE_EXISTS
	 */
	public Result<CharacterHeaderDTO> addNPC(
		long campaignId, String name, String description, 
		String icon, boolean profile);
	
	/**
	 * Loads the campaign's characters. Only GM cans call this method.
	 * Characters are not sorted. TODO pagination ?
	 * @param campaignId campaign's id.
	 * @return the campaign's characters.
	 */
	public Result<List<CharacterHeaderDTO>> getCampaignCharacters(long campaignId);
	
	/**
	 * Returns the character description : <ul>
	 * 	<li>Your note if you are a player,
	 * 	<li>All the notes if you are the GM.
	 * </ul>
	 * If you specify a timestamp, only changes are returned, so may get
	 * a CharacterDescription with only one note if only one has been updated.
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param byCharacterId the current character, who want to see the description.
	 * 		<code>null</code> for GM. Of course, it shares the same campaignId.
	 * @param timestamp <code>null</code> the first time, the description
	 * 		timestamp the next times; usefull for dealing with deltas.
	 * @return the character description.
	 */
	public Result<CharacterDescriptionDTO> getCharacterDescription(
			long campaignId, long characterId, Long byCharacterId, Date timestamp);

	/**
	 * Use it to initialise a player story board with its character description 
	 * (as viewable by itself) already completely loaded. Only character's owner
	 * can call this method.
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId the current character's id.
	 * @return the complete character description.
	 */
	public Result<CompleteCharacterDescriptionDTO> getCharacterCompleteDescription(
			long campaignId, long characterId);

	
	/**
	 * Updates a character description : <ul>
	 * 	<li>Only GM can update the description and the sheet
	 *  <li>GM can view and edit all aliases
	 *  <li>GM can view and edit all notes
	 *  <li>Character can update its own note about the character.
	 * </ul>
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param byCharacterId the character updating its note about characterId
	 * @param description description to update, if null : not updated, 
	 * 		give empty string to clear the description.
	 * @param sheet character's sheet, if null : not updated, 
	 * 		give empty string to clear the sheet.
	 * @param notes notes to update, 
	 * 		to clear one note give null string as content. For player, give
	 * 		only your own note, others notes will not be used.
	 * @param aliases GM only, modify "alias per PC".
	 * @param dead if specified, indicates if the character is dead, only for GM.
	 * @param locked if specified, indicates if the PC is locked, only for GM.
	 * @return updated data.
	 * @see Errors#IMPOSSIBLE_PROFILE
	 */
	public Result<CharacterDescriptionDTO> updateCharacterDescription(
			long campaignId, long characterId, Long byCharacterId,
			String description, String sheet, Boolean dead, Boolean locked,
			List<CharacterNoteDTO> notes, Map<Long, String> aliases);
	
	
	/**
	 * Try to create the scenes as given. Only playable characters of the 
	 * given scenes are updated, the others stay in their current scenes.
	 * 
	 * You cannot create a new scene for PC1 without dispatching PC2 in a new
	 * scene (may be the same) if they were together in the previous scene. 
	 * All the playable characters of a scene, where an updated playable 
	 * character was, must be dispatched.
	 * 
	 * Playable characters cannot have ubiquity, NPC can.
	 * 
	 * So, if : 
	 * 	- PC1 + PC2 + NPC1
	 *  - PC3
	 * 
	 * You can do :
	 * 	- scene [0] : PC1 + NPC1
	 *  - scene [1] : PC2 + NPC1
	 *  - PC3 (stays in its own scene).
	 * 
	 * @param campaignId campaign's id
	 * @param scenes new scenes (characters, intro and aliases).
	 * @return
	 * @see Errors#IMPOSSIBLE_UBIQUITY, Errors#IMPOSSIBLE_ONLY_NPCS, 
	 * 	Errors#IMPOSSIBLE_PC_NOT_DISPATCHED
	 */
	public Result<Boolean> startScenes(long campaignId, SceneToCreateDTO[] scenes);

	
	/**
	 * Temporary test method. Be carefull because this method doesn't make
	 * lots a security checks.
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param action <ul>
	 * 		<li>0 : random
	 * 		<li>1 : create a random sequence
	 * 		<li>2 : make someone talk in current scene randomly
	 * 		<li>3 : insert OFF message in previous scenes
	 * 		<li>4 : delete one message randomly
	 * 		<li>5 : make other players to roll dices (not visible :) )
	 * 		<li>6 : force to reindex some messages in previous or current scene.
	 * </ul>
	 * @return
	 */
	public Result<Boolean> justForTestsDoSomethingRandomly(
			long campaignId, long characterId, int action);


	/**
	 * The method called when player posts an action. 
	 * <b>Only for players !!!!</b>
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param action action type.
	 * @param content text of the action.
	 * @return true if ok.
	 * @see Errors#IMPOSSIBLE_LOCKED, Errors#IMPOSSIBLE_DEAD, Errors#IMPOSSIBLE,
	 * 	Errors#OUTOFDATE, Errors#IMPOSSIBLE_CLOSED, Errors#IMPOSSIBLE_PAUSED,
	 */
	public Result<Boolean> playerPostAction(
			long campaignId, long characterId, 
			long clientSceneId, Date clientSceneTimestamp,
			MessageAction action, String content);		
	
	/**
	 * The method called when player posts an OFF message. 
	 * <b>Only for players !!!!</b>
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param content text of the message.
	 * @return true if ok.
	 * @see Errors#IMPOSSIBLE_LOCKED, Errors#IMPOSSIBLE_DEAD, Errors#IMPOSSIBLE,
	 * 	Errors#OUTOFDATE, Errors#IMPOSSIBLE_CLOSED, Errors#IMPOSSIBLE_PAUSED,
	 */
	public Result<Boolean> playerPostOFF(
			long campaignId, long characterId, 
			long clientSceneId, Date clientSceneTimestamp,
			String content);	
	
	/**
	 * The method called when player rolls dices.
	 * <b>Only for players !!!!</b>
	 * 
	 * @param campaignId campaign's id.
	 * @param characterId character's id.
	 * @param the dices to roll : Map<Sides, NumberOfDices>
	 * @param content text of the message.
	 * @return true if ok.
	 * @see Errors#IMPOSSIBLE_LOCKED, Errors#IMPOSSIBLE_DEAD, Errors#IMPOSSIBLE,
	 * 	Errors#OUTOFDATE, Errors#IMPOSSIBLE_CLOSED, Errors#IMPOSSIBLE_PAUSED,
	 */
	public Result<Boolean> playerRollDices(
			long campaignId, long characterId, 
			long clientSceneId, Date clientSceneTimestamp,
			Map<Integer, Integer> dices, String content);
}
